#include "iic.h"
#include "misc.h"
#include <stm32f10x_gpio.h>
#include <stm32f10x_exti.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_i2c.h>

#define IIC_M_A 0x77
#define IIC_S_A IIC_M_A

void I2C_GPIO_Config()
{
    GPIO_InitTypeDef i2c;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    i2c.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    i2c.GPIO_Speed = GPIO_Speed_50MHz;
    // 开漏输出，配置成开漏输出之后，就可以通过外部配置来指定电平，比如上拉电阻；
    // 不能是PP，那样就是有芯片内部来给出高低电平了
    i2c.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_Init(GPIOB, &i2c);
}

void I2C1_Init()
{
    I2C_InitTypeDef i2c;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    I2C_DeInit(I2C1);

    i2c.I2C_Mode = I2C_Mode_I2C; // I2C接口可以用于I2C通信以及MBus通信
    // 占空比，low/high的比值，一个是16/9，一个就是2；
    // 选择哪一个是由I2C的速度决定的，快速和标准所需要选择的速度是不一样的
    // 标准模式：4.7/4
    // 快速模式：1.3/0.6
    // 快速模式+：0.5/0.26
    i2c.I2C_DutyCycle = I2C_DutyCycle_2;
    // 从机1地址，对应的寄存器是OAR2，起始如果作为从机而言，这个地址作用不大
    // 但是，如果是主机的话，必须要设置，因为I2C是通过地址找到从机的
    i2c.I2C_OwnAddress1 = IIC_M_A;
    i2c.I2C_Ack = I2C_Ack_Enable; // 配置应答，无论主从机都需要应答
    // 设置地址位数，这里设置7位
    i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    // 只要低于400kHz都可以
    i2c.I2C_ClockSpeed = 10000;

    I2C_Init(I2C1, &i2c);
    I2C_Cmd(I2C1, ENABLE);
}

void I2C_Write(u8 addr, u8 data)
{
    I2C_AcknowledgeConfig(I2C1, ENABLE);
    I2C_GenerateSTART(I2C1, ENABLE);
    // EVX参考手册里面的I2C主机模式里面的时序图描述
    // EV5，EV5说明确认开始状态已经设置到了I2C Bus上面了
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 
    // 这里的地址是8bit（7bit + r/w bit）
    // TODO 这源码需要好好看看，读写地址处理是不一样的
    I2C_Send7bitAddress(I2C1, IIC_S_A, I2C_Direction_Transmitter);
    // EV6
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr);    
    // EV8
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    I2C_SendData(I2C1, data);

    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    I2C_GenerateSTOP(I2C1, ENABLE);
}

void I2C_Read(u8 addr){
    
    // 首先由master发起会话
    // 配置主发送器
    // 高速OLED设备我要访问哪一个地址
    I2C_AcknowledgeConfig(I2C1, ENABLE);
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)));
    I2C_Send7bitAddress(I2C1, IIC_S_A, I2C_Direction_Transmitter);

    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)));
    I2C_SendData(I2C1, addr);

    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)));
    // 转换方向，有Slave传输数据
    // 配置主接收器
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))); // EV5
    I2C_Send7bitAddress(I2C1, IIC_S_A, I2C_Direction_Receiver);

    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))); // EV6
    // 关闭SB，因为
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);

    while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))); // EV7
    return I2C_ReceiveData(I2C1);
}

void I2C2_GPIO_Config(){
    GPIO_InitTypeDef i2c;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    i2c.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    i2c.GPIO_Speed = GPIO_Speed_50MHz;
    // 开漏输出，配置成开漏输出之后，就可以通过外部配置来指定电平，比如上拉电阻；
    // 不能是PP，那样就是有芯片内部来给出高低电平了
    i2c.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_Init(GPIOB, &i2c);
}